package horoclient;

import javax.swing.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import common.*;
import client.*;

//This is the main game lobby.

public class SwingLobby extends JFrame implements Observer{
	private static final long serialVersionUID = 8307789846396147611L;
	
	private Observer nc; //Network thread.
	private MessageSender m;
	private final ClientGameState cgs;
	private final JLabel name;
	private String [] rounds = {"Loading Rounds..."};
	private final JTextArea area = new JTextArea("Select a Round : ");
	private final JTextPane chatBuf = new JTextPane();
	private final JTextField chat = new JTextField("");
	private final JComboBox combobox = new JComboBox(rounds);
	private final JButton register = new JButton("Register");
	private String playerName = "Anonymous";
	private JFrame sr; //SwingRound
	private Window scoreboard;
	private boolean roundOpened = false;
	private Round [] round;
	private static String header = "<html><br><br><br><br><font color=white>Name : ";
	private static String footer = "</font></html>";
	
	public SwingLobby(Observer nc, final ClientGameState cgs) {
		m = new MessageSender(nc);
		m.send(new RoundRequest());
		
		ImagePanel panel = new ImagePanel(new ImageIcon(SwingLobby.class.getResource("horo3.JPG")).getImage());
		
		setSize(640,480);
		setTitle("Game Lobby");
		this.nc = nc;
		this.cgs = cgs;
		
		name = new JLabel(header + playerName + footer);
		
		//JPanel panel = new JPanel();
		panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        panel.setLayout(new GridLayout(1,2,1,1));
        
        //Chat (Left)
        JPanel chatP = new JPanel();
        chatP.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        chatP.setLayout(new BoxLayout(chatP, BoxLayout.Y_AXIS));
        panel.add(chatP);
        
        JLabel chatLabel = new JLabel("<html><font color=white>Lobby Chat</font></html>");
        chatLabel.setAlignmentY(0f);
        chatBuf.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        chatBuf.setEditable(false);
        chatBuf.setPreferredSize(new Dimension(400,400));
        chat.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        chat.setPreferredSize(new Dimension(400,30));
        chat.setFocusable(true);
        chatP.add(chatLabel);
        chatP.add(Box.createRigidArea(new Dimension(0, 5)));
        chatP.add(chatBuf);
        chatP.add(Box.createRigidArea(new Dimension(0, 15)));
        chatP.add(chat);
        chat.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent e){
				sendChatMessage();
			}
        });
        
        //Other Stuff (Right)
        JPanel otherP = new JPanel();
        
        otherP.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        otherP.setLayout(new GridLayout(2,1,1,1));
        panel.add(otherP);
        JPanel nameP = new JPanel();
        JPanel roundP = new JPanel();
        nameP.setBorder(BorderFactory.createEmptyBorder(10, 10, 10,10));
        roundP.setBorder(BorderFactory.createEmptyBorder(10,10, 10, 10));
        otherP.add(roundP);
        otherP.add(nameP);
        
        nameP.setLayout(new BoxLayout(nameP, BoxLayout.Y_AXIS));
        roundP.setLayout(new BoxLayout(roundP, BoxLayout.Y_AXIS));
        
        nameP.add(name);
        JButton jb = new JButton("Change Name");
        jb.setEnabled(false);
        jb.addActionListener( new ActionListener(){ 
        	public void actionPerformed(ActionEvent e){
				getAndSetPlayerName();
			}
        });
        nameP.add(Box.createRigidArea(new Dimension(0, 15)));
        //nameP.add(jb);
        
        JScrollPane pane = new JScrollPane();
         

        area.setLineWrap(true);
        area.setWrapStyleWord(true);
        area.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        area.setEditable(false);
        pane.getViewport().add(area);
        
        
        
        
        combobox.setSelectedIndex(0);
        combobox.setPreferredSize(new Dimension(240, 22));
        combobox.setMaximumSize(new Dimension(240, 22));
        combobox.addItemListener(new ItemListener() {
        	public void itemStateChanged( ItemEvent ie) {
                if (ie.getStateChange() == ItemEvent.SELECTED) {
                    JComboBox combo = (JComboBox) ie.getSource();
                    int index = combo.getSelectedIndex();
                    Round r = getRound(index);
                    if (r != null) {
                    	String [] b = r.toString().split("\n");
                    	String s = b[0] + "\nNumber of Players: " + r.numberOfPlayers() + "\nPlayers: ";
                    	for (Player P : r.getPlayers())
                    		s = s + " , " + P.getName();
                    	s = s.replace(":  ,",": ");
                    	area.setText(s);
                    }
                    register.setText("Register");
                    if (r != null && cgs.getCurrentRound() != null) {
                    	if (r.equals(cgs.getCurrentRound())) {
                    		register.setText("Enter Round");
                    		if (!roundOpened && r.getCurrentPhase() != PhaseEnum.RESULTS) roundWindow();
                    	}
                    }
                    if (r!= null && r.getCurrentPhase() == PhaseEnum.RESULTS)
                    		register.setText("View Results");
                }
        	}
        });
        
        register.setPreferredSize(new Dimension(100,30));
        register.addActionListener( new ActionListener(){
        	public void actionPerformed(ActionEvent e) {
        		Round r = getRound(combobox.getSelectedIndex());
        		if (register.getText().equals("Register")) {
        			String name = getRegisterName();
        			Register reg = new Register(name,r);
        			m.send(reg);
        			if (sr != null) {sr.dispose();sr=null;}
        		} else if (register.getText().equals("Enter Round")) {
        			roundWindow();
        		} else {
        			resultsWindow();
        		}
        	}
        });
        roundP.add(area);
        roundP.add(Box.createRigidArea(new Dimension(0, 15)));
        roundP.add(combobox);
        roundP.add(Box.createRigidArea(new Dimension(0, 15)));
        roundP.add(register);
        
        chatP.setOpaque(false);
        otherP.setOpaque(false);
        nameP.setOpaque(false);
        roundP.setOpaque(false);
        chatBuf.setOpaque(false);
        chatP.setOpaque(false);
        
        
        this.add(panel);
        this.pack();
        this.validate();
        this.setDefaultCloseOperation ( JFrame.DISPOSE_ON_CLOSE );
        this.setResizable(false);
		
		cgs.addObserver(this);
	}
	
	//Called whenever an update in the gamestate is detected.
	//This is the main update method (executed by the EDT)
	public void statusUpdate() {
		updateRoundList();
		updateChatList(cgs.getChat());
		if (cgs.hasAuctionError()) JOptionPane.showMessageDialog(null, "Error : Invalid Ask or Bid");
		if (cgs.hasRegistrationError()) {
			if (cgs.getCurrentRound() != null)
				JOptionPane.showMessageDialog(null, "Error : You can not register in more than one round.");
			else 
				JOptionPane.showMessageDialog(null, "Error : You can not register for this round.");
		}
		roundPopupStateUpdate();
		
		validate();repaint();
	}
	private void roundPopupStateUpdate() {
		Round r = cgs.getCurrentRound();
		if (r != null && r.getCurrentPhase() == PhaseEnum.RESULTS)
			roundOpened = false;
	}
	// This updates the round list (including the combobox)
	// as viewed by the player.
	public void updateRoundList() {
		final Round [] r = cgs.getRounds();
		final String [] a = new String [r.length];
		int N = r.length;
		int i = combobox.getSelectedIndex();
		int ii = 0;
		while (N-->0) {
			int j = r[N].getID();
			a[N] = "Round #" + j;
			if (N == i) ii = j;
		}
		round = r;
		updateRoundBox(a,r,ii);
	}
	//This updates the box with all the rounds.
	private void updateRoundBox(String [] a, Round [] r, int j) {
		combobox.removeAllItems();
		for (int i = 0; i<a.length; ++i) {
			combobox.addItem(a[i]);
			if (r[i].getID() == j)
				combobox.setSelectedIndex(i);
		}
	}
	//This updates the chat area windows.
	public void updateChatList(String s) {
		chatBuf.setText(s);
	}
	
	//This updates the state of the lobby
	// (Called by the network thread)
	public void update(Observable o, Object arg) {
		SwingUtilities.invokeLater(new Runnable(){public void run(){statusUpdate();}});
	}
	
	//These methods control the initial querying for the player name.
	public void getAndSetPlayerName() {
		playerName = getPlayerName();
		name.setText(header + playerName + footer);
	}
	private String getRegisterName() { return playerName;}
	private String getPlayerName() {
		String ish = "Please Enter Your Player Name (AlphaNumeric Only) : ";
		String result = JOptionPane.showInputDialog(ish);
		String result2 = (result == null) ? "" : new String(result);
		while (result == null || result2.matches(".*[^A-Za-z0-9 ].*") || result.length() < 3 || result.length()>15) {
			System.err.println("Result : " + result);
			ish = "Your name must be at least 3-15 characters long and be alphanumeric :";
			result = JOptionPane.showInputDialog(ish);
			result2 = (result == null) ? "" : new String(result);
		}
		return result;
	}
	
	// This sends a chat packet to the server;
	private void sendChatMessage() {
		String msg = chat.getText();
		chat.setText("");
		m.send(new ChatPacket(getRegisterName(),msg));
	}
	
	// This method gets the round that is selected in the combobox.
	private Round getSelectedRound() { 
		return getRound(combobox.getSelectedIndex());
	}
	// This method gets the round at the current index in round list.
	private Round getRound(int index) {
		return (round == null || index < 0 || index > round.length) ? cgs.getRound(index) : round[index];
	}
	
	// Displays the scoreboard.
	// If one already exists, closes the previous scoreboard,
	// and reopens a new one.
	private void resultsWindow() {
		if (scoreboard != null) {
			scoreboard.dispose();
			scoreboard=null;
		}
		scoreboard = new SwingScoreboard(getSelectedRound());
		scoreboard.setLocation(100,100);
		scoreboard.setVisible(true);
	}

	//Starts the round window.
	//if a round window already exists,
	//then focuses that round window.
	private void roundWindow() {
		roundOpened = true;
		if (sr != null) {
			sr.setExtendedState(NORMAL);
			sr.requestFocus();
		} else {
		final SwingRound SR = new SwingRound(nc,cgs);
		//Add death listeners for this window.
		SR.addWindowListener(new WindowListenerE(){
			public void windowClosing(WindowEvent e) { 
				closeAll(); sr = null;
			}
			public void windowClosed(WindowEvent e) { windowClosing(e);}
		});
		this.sr = SR;
		//Make sure to kill our child window when we die.
		this.addWindowListener(new WindowListenerE(){
			public void windowClosing(WindowEvent e) {
				SR.closeAll();
				closeAll();
				sr = null;
			}
			public void windowClosed(WindowEvent e) { windowClosing(e);}
		});
		SwingUtilities.invokeLater(new Runnable(){public void run(){SR.setVisible(true);}});
		}
		
	}
	//This private class can be extende to deal with window cleanup on disconnect
	//and window close
	private class WindowListenerE implements WindowListener {
		public void windowActivated(WindowEvent e) {}
		public void windowClosed(WindowEvent e) { }
		public void windowClosing(WindowEvent e) { }
		public void windowDeactivated(WindowEvent e) {}
		public void windowDeiconified(WindowEvent e) {}
		public void windowIconified(WindowEvent e) {}
		public void windowOpened(WindowEvent e) {}
	}
	
	//This method closes all the children windows.
	protected void closeAll() {
		if (scoreboard != null) scoreboard.dispose(); scoreboard=null;
		if (sr != null) sr.dispose(); sr=null;
	}
	
	//???
	class ImagePanel extends JPanel {

		private static final long serialVersionUID = 7740228435573197143L;
		private Image img;

		  public ImagePanel(String img) {
		    this(new ImageIcon(img).getImage());
		  }

		  public ImagePanel(Image img) {
		    this.img = img;
		    Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
		    setPreferredSize(size);
		    setMinimumSize(size);
		    setMaximumSize(size);
		    setSize(size);
		    setLayout(null);
		  }

		  public void paintComponent(Graphics g) {
		    g.drawImage(img, 0, 0, null);
		  }

		}
}
